import Module from './Module';
import $ from 'jquery';


function array_merge(arr1, arr2) {
    arr1.push.apply(arr1, arr2);
    return arr1;
}

export default class Formatter extends Module {

	_init() {
		this.editor = this._module;
		this._allowedTags = array_merge(['br', 'span', 'a', 'img', 'b', 'strong', 'i', 'strike', 'u', 'font', 'p', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'h1', 'h2', 'h3', 'h4', 'hr'], this.opts.allowedTags).filter((t) => !!t);
		this._allowedAttributes = $.extend({
			img: ['src', 'alt', 'width', 'height', 'data-non-image'],
			a: ['href', 'target'],
			font: ['color'],
			code: ['class']
		}, this.opts.allowedAttributes);
		this._allowedStyles = $.extend({
			span: ['color', 'font-size'],
			b: ['color'],
			i: ['color'],
			strong: ['color'],
			strike: ['color'],
			u: ['color'],
			p: ['margin-left', 'text-align'],
			h1: ['margin-left', 'text-align'],
			h2: ['margin-left', 'text-align'],
			h3: ['margin-left', 'text-align'],
			h4: ['margin-left', 'text-align']
		}, this.opts.allowedStyles);
		return this.editor.body.on('click', 'a', e => false);
	}

	decorate($el) {
		if ($el == null) {
			$el = this.editor.body;
		}
		this.editor.trigger('decorate', [$el]);
		return $el;
	}

	undecorate($el) {
		if ($el == null) {
			$el = this.editor.body.clone();
		}
		this.editor.trigger('undecorate', [$el]);
		return $el;
	}

	autolink($el) {
		let $link;
		let $node;
		let findLinkNode;
		let k;
		let lastIndex;
		let len;
		let linkNodes;
		let match;
		let re;
		let replaceEls;
		let subStr;
		let text;
		let uri;
		$el = $el || this.editor.body;
		linkNodes = [];
		findLinkNode = $parentNode => $parentNode.contents().each((i, node) => {
			let $node;
			let text;
			$node = $(node);
			if ($node.is('a') || $node.closest('a, pre', $el).length) {
				return;
			}
			if (!$node.is('iframe') && $node.contents().length) {
				return findLinkNode($node);
			} else if ((text = $node.text()) && /https?:\/\/|www\./ig.test(text)) {
				return linkNodes.push($node);
			}
		});
		findLinkNode($el);
		re = /(https?:\/\/|www\.)[\w\-\.\?&=\/#%:,@\!\+]+/ig;
		for (k = 0, len = linkNodes.length; k < len; k++) {
			$node = linkNodes[k];
			text = $node.text();
			replaceEls = [];
			match = null;
			lastIndex = 0;
			while ((match = re.exec(text)) !== null) {
				subStr = text.substring(lastIndex, match.index);
				replaceEls.push(document.createTextNode(subStr));
				lastIndex = re.lastIndex;
				uri = /^(http(s)?:\/\/|\/)/.test(match[0]) ? match[0] : `http://${match[0]}`;
				$link = $(`<a href="${uri}" rel="nofollow"></a>`).text(match[0]);
				replaceEls.push($link[0]);
			}
			replaceEls.push(document.createTextNode(text.substring(lastIndex)));
			$node.replaceWith($(replaceEls));
		}
		return $el;
	}

	format($el) {
		let $node;
		let blockNode;
		let k;
		let l;
		let len;
		let len1;
		let n;
		let node;
		let ref;
		let ref1;
		if ($el == null) {
			$el = this.editor.body;
		}
		if ($el.is(':empty')) {
			$el.append(`<p>${this.editor.util.phBr}</p>`);
			return $el;
		}
		ref = $el.contents();
		for (k = 0, len = ref.length; k < len; k++) {
			n = ref[k];
			this.cleanNode(n, true);
		}
		ref1 = $el.contents();
		for (l = 0, len1 = ref1.length; l < len1; l++) {
			node = ref1[l];
			$node = $(node);
			if ($node.is('br')) {
				if (typeof blockNode !== "undefined" && blockNode !== null) {
					blockNode = null;
				}
				$node.remove();
			} else if (this.editor.util.isBlockNode(node)) {
				if ($node.is('li')) {
					if (blockNode && blockNode.is('ul, ol')) {
						blockNode.append(node);
					} else {
						blockNode = $('<ul/>').insertBefore(node);
						blockNode.append(node);
					}
				} else {
					blockNode = null;
				}
			} else {
				if (!blockNode || blockNode.is('ul, ol')) {
					blockNode = $('<p/>').insertBefore(node);
				}
				blockNode.append(node);
				if (this.editor.util.isEmptyNode(blockNode)) {
					blockNode.append(this.editor.util.phBr);
				}
			}
		}
		return $el;
	}

	cleanNode(node, recursive) {
		let $blockEls;
		let $childImg;
		let $node;
		let $p;
		let $td;
		let allowedAttributes;
		let attr;
		let contents;
		let isDecoration;
		let k;
		let l;
		let len;
		let len1;
		let n;
		let ref;
		let ref1;
		let text;
		let textNode;
		$node = $(node);
		if (!($node.length > 0)) {
			return;
		}
		if ($node[0].nodeType === 3) {
			text = $node.text().replace(/(\r\n|\n|\r)/gm, '');
			if (text) {
				textNode = document.createTextNode(text);
				$node.replaceWith(textNode);
			} else {
				$node.remove();
			}
			return;
		}
		contents = $node.is('iframe') ? null : $node.contents();
		isDecoration = this.editor.util.isDecoratedNode($node);
		if ($node.is(this._allowedTags.join(',')) || isDecoration) {
			if ($node.is('a') && ($childImg = $node.find('img')).length > 0) {
				$node.replaceWith($childImg);
				$node = $childImg;
				contents = null;
			}
			if ($node.is('td') && ($blockEls = $node.find(this.editor.util.blockNodes.join(','))).length > 0) {
				$blockEls.each(((() => (i, blockEl) => $(blockEl).contents().unwrap()))(this));
				contents = $node.contents();
			}
			if ($node.is('img') && $node.hasClass('uploading')) {
				$node.remove();
			}
			if (!isDecoration) {
				allowedAttributes = this._allowedAttributes[$node[0].tagName.toLowerCase()];
				ref = $.makeArray($node[0].attributes);
				for (k = 0, len = ref.length; k < len; k++) {
					attr = ref[k];
					if (attr.name === 'style') {
						continue;
					}
					if (!((allowedAttributes != null) && (ref1 = attr.name, allowedAttributes.indexOf(ref1) >= 0))) {
						$node.removeAttr(attr.name);
					}
				}
				this._cleanNodeStyles($node);
				if ($node.is('span') && $node[0].attributes.length === 0) {
					$node.contents().first().unwrap();
				}
			}
		} else if ($node[0].nodeType === 1 && !$node.is(':empty')) {
			if ($node.is('div, article, dl, header, footer, tr')) {
				$node.append('<br/>');
				contents.first().unwrap();
			} else if ($node.is('table')) {
				$p = $('<p/>');
				$node.find('tr').each((i, tr) => $p.append(`${$(tr).text()}<br/>`));
				$node.replaceWith($p);
				contents = null;
			} else if ($node.is('thead, tfoot')) {
				$node.remove();
				contents = null;
			} else if ($node.is('th')) {
				$td = $('<td/>').append($node.contents());
				$node.replaceWith($td);
			} else {
				contents.first().unwrap();
			}
		} else {
			$node.remove();
			contents = null;
		}
		if (recursive && (contents != null) && !$node.is('pre')) {
			for (l = 0, len1 = contents.length; l < len1; l++) {
				n = contents[l];
				this.cleanNode(n, true);
			}
		}
		return null;
	}

	_cleanNodeStyles($node) {
		let allowedStyles;
		let pair;
		let ref1;
		let styleStr;
		let styles;
		styleStr = $node.attr('style');
		if (!styleStr) {
			return;
		}
		$node.removeAttr('style');
		allowedStyles = this._allowedStyles[$node[0].tagName.toLowerCase()];
		if (!(allowedStyles && allowedStyles.length > 0)) {
			return $node;
		}
		styles = {};
		styleStr.split(';').forEach((style) => {
			style = style.trim();
			pair = style.split(':');
			if (pair.length == 2) {
				if (ref1 = pair[0], allowedStyles.indexOf(ref1) >= 0) {
					styles[$.trim(pair[0])] = $.trim(pair[1]);
				}
			}
		})
		if (Object.keys(styles).length > 0) {
			$node.css(styles);
		}
		return $node;
	}

	clearHtml(html, lineBreak) {
		let container;
		let contents;
		let result;
		if (lineBreak == null) {
			lineBreak = true;
		}
		container = $('<div/>').append(html);
		contents = container.contents();
		result = '';
		contents.each(((_this => (i, node) => {
			let $node;
			let children;
			if (node.nodeType === 3) {
				return result += node.nodeValue;
			} else if (node.nodeType === 1) {
				$node = $(node);
				children = $node.is('iframe') ? null : $node.contents();
				if (children && children.length > 0) {
					result += _this.clearHtml(children);
				}
				if (lineBreak && i < contents.length - 1 && $node.is('br, p, div, li,tr, pre, address, artticle, aside, dl, figcaption, footer, h1, h2,h3, h4, header')) {
					return result += '\n';
				}
			}
		}))(this));
		return result;
	}

	beautify($contents) {
		let uselessP;
		uselessP = $el => !!($el.is('p') && !$el.text() && $el.children(':not(br)').length < 1);
		return $contents.each((i, el) => {
			let $el;
			let invalid;
			$el = $(el);
			invalid = $el.is(':not(img, br, col, td, hr, [class^="simditor-"]):empty');
			if (invalid || uselessP($el)) {
				$el.remove();
			}
			return $el.find(':not(img, br, col, td, hr, [class^="simditor-"]):empty').remove();
		});
	}
}

Formatter.pluginName = 'Formatter';
Formatter.prototype.opts = {
	allowedTags: [],
	allowedAttributes: {},
	allowedStyles: {}
};